<template>
  <el-dialog
    v-model="dialogVisible"
    :title="$t('pageCertificates.modal.generateACertificateSigningRequest')"
    width="50%"
    @close="resetForm()"
  >
    <el-form
      ref="generateCsrFormRef"
      :model="form"
      :rules="rules"
      label-position="top"
    >
      <el-row :gutter="10">
        <el-col :span="8">
          <el-form-item
            :label="$t('pageCertificates.modal.certificateType')"
            prop="certificateType"
          >
            <el-select
              v-model="form.certificateType"
              placeholder="Select"
              style="width: 100%"
            >
              <el-option
                v-for="item in certificateOptions"
                :key="item.value"
                :label="item.text"
                :value="item.value"
              />
            </el-select>
          </el-form-item>
        </el-col>
        <el-col :span="8">
          <el-form-item
            :label="$t('pageCertificates.modal.country')"
            prop="country"
          >
            <el-select
              v-model="form.country"
              placeholder="Select"
              style="width: 100%"
            >
              <el-option
                v-for="item in countryOptions"
                :key="item.value"
                :label="item.text"
                :value="item.value"
              />
            </el-select>
          </el-form-item>
        </el-col>
        <el-col :span="8">
          <el-form-item
            :label="$t('pageCertificates.modal.privateKey')"
            prop="keyPairAlgorithm"
          >
            <el-select
              v-model="form.keyPairAlgorithm"
              placeholder="Select"
              style="width: 100%"
            >
              <el-option
                v-for="item in keyPairAlgorithmOptions"
                :key="item"
                :label="item"
                :value="item"
              />
            </el-select>
          </el-form-item>
        </el-col>
      </el-row>
      <el-row :gutter="10">
        <el-col :span="8">
          <el-form-item
            :label="$t('pageCertificates.modal.state')"
            prop="state"
          >
            <el-input v-model="form.state" />
          </el-form-item>
        </el-col>
        <el-col :span="8">
          <el-form-item :label="$t('pageCertificates.modal.city')" prop="city">
            <el-input v-model="form.city" />
          </el-form-item>
        </el-col>
        <el-col :span="8">
          <el-form-item
            :label="$t('pageCertificates.modal.keyCurveId')"
            prop="keyCurveId"
            v-if="form.keyPairAlgorithm === 'EC'"
          >
            <el-select
              v-model="form.keyCurveId"
              placeholder="Select"
              style="width: 100%"
            >
              <el-option
                v-for="item in keyCurveIdOptions"
                :key="item"
                :label="item"
                :value="item"
              />
            </el-select>
          </el-form-item>
          <el-form-item
            :label="$t('pageCertificates.modal.keyBitLength')"
            prop="keyCurveId"
            v-if="form.keyPairAlgorithm === 'RSA'"
          >
            <el-select
              v-model="form.keyBitLength"
              placeholder="Select"
              style="width: 100%"
            >
              <el-option
                v-for="item in keyBitLengthOptions"
                :key="item"
                :label="item"
                :value="item"
              />
            </el-select>
          </el-form-item>
        </el-col>
      </el-row>
      <el-row :gutter="10">
        <el-col :span="8">
          <el-form-item
            :label="$t('pageCertificates.modal.companyName')"
            prop="companyName"
          >
            <el-input v-model="form.companyName" />
          </el-form-item>
        </el-col>
        <el-col :span="8">
          <el-form-item
            :label="$t('pageCertificates.modal.companyUnit')"
            prop="companyUnit"
          >
            <el-input v-model="form.companyUnit" />
          </el-form-item>
        </el-col>
      </el-row>
      <el-row :gutter="10">
        <el-col :span="8">
          <el-form-item
            :label="$t('pageCertificates.modal.commonName')"
            prop="commonName"
          >
            <el-input v-model="form.commonName" />
          </el-form-item>
        </el-col>
        <el-col :span="8">
          <el-form-item prop="challengePassword">
            <template #label>
              {{ $t('pageCertificates.modal.challengePassword') }}
              -
              <span class="text-gray-400">
                {{ $t('global.form.optional') }}
              </span>
            </template>
            <el-input v-model="form.challengePassword" />
          </el-form-item>
        </el-col>
      </el-row>
      <el-row :gutter="10">
        <el-col :span="8">
          <el-form-item prop="contactPerson">
            <template #label>
              {{ $t('pageCertificates.modal.contactPerson') }}
              -
              <span class="text-gray-400">
                {{ $t('global.form.optional') }}
              </span>
            </template>
            <el-input v-model="form.contactPerson" />
          </el-form-item>
        </el-col>
        <el-col :span="8">
          <el-form-item prop="emailAddress">
            <template #label>
              {{ $t('pageCertificates.modal.emailAddress') }}
              -
              <span class="text-gray-400"
                >{{ $t('global.form.optional') }}
              </span>
            </template>
            <el-input v-model="form.emailAddress" />
          </el-form-item>
        </el-col>
      </el-row>
      <el-row :gutter="10">
        <el-col :span="16">
          <el-form-item prop="emailAddress">
            <template #label>
              {{ $t('pageCertificates.modal.alternateName') }}
              -
              <span class="text-gray-400"
                >{{ $t('global.form.optional') }}
              </span>
            </template>
            <el-select
              v-model="form.alternateName"
              multiple
              filterable
              allow-create
              default-first-option
              :reserve-keyword="false"
              placeholder=""
              style="width: 240px"
            >
            </el-select>
          </el-form-item>
        </el-col>
      </el-row>
    </el-form>
    <template #footer>
      <div class="dialog-footer">
        <el-button @click="dialogVisible = false">
          {{ $t('global.action.cancel') }}
        </el-button>
        <el-button type="primary" @click="onOkGenerateCsrModal">
          {{ $t('pageCertificates.generateCsr') }}
        </el-button>
      </div>
    </template>
  </el-dialog>

  <el-dialog
    v-model="csrStringVisible"
    :title="$t('pageCertificates.modal.certificateSigningRequest')"
    width="500px"
    @close="onHiddenCsrStringModal"
  >
    {{ csrString }}
    <template #footer>
      <div class="dialog-footer">
        <el-button
          type="primary"
          :icon="csrStringCopied ? '' : CopyDocument"
          class="mr-2"
          @click="copyCsrString"
        >
          {{
            csrStringCopied
              ? $t('global.action.copied')
              : $t('global.action.copy')
          }}
        </el-button>
        <a
          :href="`data:text/json;charset=utf-8,${csrString}`"
          download="certificate.txt"
        >
          {{ $t('global.action.download') }}
        </a>
      </div>
    </template>
  </el-dialog>
</template>

<script setup lang="ts">
import { CopyDocument } from '@element-plus/icons-vue';
import useVuelidateTool from '@/hooks/useVuelidateTool';

import { COUNTRY_LIST } from './CsrCountryCodes';
import { CERTIFICATE_TYPES } from '@/store/UserSecurity/Certificates/CertificatesStore';
import { useCertificatesStore } from '@/store/UserSecurity/Certificates/CertificatesStore';

const CertificatesStore = useCertificatesStore();
const { useVuelidate, required, requiredIf, elementInputValidator } =
  useVuelidateTool();

const dialogVisible = ref(false);
const generateCsrFormRef = ref();

const form = reactive({
  certificateType: null,
  country: null,
  state: null,
  city: null,
  companyName: null,
  companyUnit: null,
  commonName: null,
  challengePassword: null,
  contactPerson: null,
  emailAddress: null,
  keyCurveId: null,
  keyBitLength: null,
  keyPairAlgorithm: null,
  alternateName: [],
});

const certificateOptions = computed(() =>
  CERTIFICATE_TYPES.reduce((arr: any[], cert: any) => {
    if (cert.type === 'TrustStore Certificate') return arr;
    arr.push({
      text: cert.label,
      value: cert.type,
    });
    return arr;
  }, []),
);

const countryOptions = computed(() =>
  COUNTRY_LIST.map((country) => ({
    text: country.label,
    value: country.code,
  })),
);

const keyPairAlgorithmOptions = ['EC', 'RSA'];

const keyCurveIdOptions = ['prime256v1', 'secp521r1', 'secp384r1'];

const keyBitLengthOptions = [2048];

// Set vuelidate rules.
const v$ = useVuelidate(
  {
    certificateType: {
      required,
    },
    country: {
      required,
    },
    state: {
      required,
    },
    city: {
      required,
    },
    companyName: { required },
    companyUnit: { required },
    commonName: { required },
    keyPairAlgorithm: {
      required,
    },
    keyCurveId: {
      reuired: requiredIf(function () {
        return form.keyPairAlgorithm === 'EC';
      }),
    },
    keyBitLength: {
      reuired: requiredIf(function () {
        return form.keyPairAlgorithm === 'RSA';
      }),
    },
  },
  form,
);

// validators
const rules = computed(() => {
  return {
    certificateType: [
      {
        trigger: 'change',
        validator: elementInputValidator.value(v$, 'certificateType'),
      },
    ],
    country: [
      {
        trigger: 'change',
        validator: elementInputValidator.value(v$, 'country'),
      },
    ],
    state: [
      {
        trigger: 'change',
        validator: elementInputValidator.value(v$, 'state'),
      },
    ],
    city: [
      {
        trigger: 'change',
        validator: elementInputValidator.value(v$, 'city'),
      },
    ],
    companyName: [
      {
        trigger: 'change',
        validator: elementInputValidator.value(v$, 'companyName'),
      },
    ],
    companyUnit: [
      {
        trigger: 'change',
        validator: elementInputValidator.value(v$, 'companyUnit'),
      },
    ],
    commonName: [
      {
        trigger: 'change',
        validator: elementInputValidator.value(v$, 'commonName'),
      },
    ],
    keyPairAlgorithm: [
      {
        trigger: 'change',
        validator: elementInputValidator.value(v$, 'keyPairAlgorithm'),
      },
    ],
    keyCurveId: [
      {
        trigger: 'change',
        validator: elementInputValidator.value(v$, 'keyCurveId'),
      },
    ],
    keyBitLength: [
      {
        trigger: 'change',
        validator: elementInputValidator.value(v$, 'keyBitLength'),
      },
    ],
  };
});

const handleSubmit = async () => {
  v$.value.$touch();
  if (v$.value.$invalid) return;
  CertificatesStore.generateCsr(form)
    .then(({ data: { CSRString } }: any) => {
      csrString.value = CSRString;
      csrStringVisible.value = true;
      v$.value.$reset();
    })
    .finally(() => {
      closeModal();
    });
};

const resetForm = () => {
  for (let key of Object.keys(form)) {
    if (key === 'alternateName') {
      form[key] = [];
    } else {
      (form as { [key: string]: any })[key] = null;
    }
  }
  closeModal();
};

const closeModal = () => {
  nextTick(() => {
    dialogVisible.value = false;
  });
};

const onOkGenerateCsrModal = () => {
  handleSubmit();
};

const csrStringVisible = ref(false);
const csrString = ref('签名xxx');
const csrStringCopied = ref(false);
const onHiddenCsrStringModal = () => {
  csrString.value = '';
  resetForm();
};

const copyCsrString = () => {
  // prevent modal close
  navigator.clipboard.writeText(csrString.value).then(() => {
    // Show copied text for 5 seconds
    csrStringCopied.value = true;
    setTimeout(() => {
      csrStringCopied.value = false;
    }, 5000 /*5 seconds*/);
  });
};

defineExpose({
  dialogVisible,
});
</script>

<style lang="scss" scoped></style>
